import type {
    UniversalFlowNode,
    UniversalFlowEdge,
    UniversalFlowNodeData,
    NodeSemanticType,
    SourceFormat
} from '@/models/universalFlow';
import { v4 as uuidv4 } from 'uuid';
import type { ParseUniversalResult } from '../universalParser'; // Reuse the result interface

// --- Internal Transformer Logic (Adapted from xmlToUniversalTransformer.ts) ---

interface TransformResult {
    nodes: UniversalFlowNode[];
    edges: UniversalFlowEdge[];
    rootId: string | null;
}

/**
 * Transforms a parsed XML Document object into the Universal Flow format.
 * This is now an internal helper function.
 *
 * @param xmlDoc The XML Document object.
 * @returns An object containing the list of nodes, edges, and the root node ID.
 */
function transformDomToUniversal(xmlDoc: Document): TransformResult {
    const nodes: UniversalFlowNode[] = [];
    const edges: UniversalFlowEdge[] = [];
    let rootId: string | null = null;

    // Helper function for recursive traversal - ADD parentPath parameter
    function traverse(xmlNode: Node, parentUniversalId: string | null, level: number, order: number, parentPath: string): string | null {
        let currentUniversalId: string | null = null;
        let currentNodePath: string = ''; // Initialize path for the current node

        switch (xmlNode.nodeType) {
            case Node.ELEMENT_NODE:
                const element = xmlNode as Element;
                currentUniversalId = uuidv4();

                // --- Path Calculation for Element ---
                const elementSegment = '/' + element.tagName;
                // TODO: Add sibling index [n] for elements with the same tag name if needed for uniqueness
                currentNodePath = parentPath ? parentPath + elementSegment : elementSegment; // Handle root case

                const attributesRecord: Record<string, string> = Array.from(element.attributes).reduce((acc, attr) => {
                    acc[attr.name] = attr.value;
                    return acc;
                }, {} as Record<string, string>);

                const nodeData: UniversalFlowNodeData = {
                    sourceElement: element, // Keep reference to original DOM node
                    name: element.tagName,
                    nodeSemanticType: 'element',
                    attributes: Object.keys(attributesRecord).length > 0 ? attributesRecord : {},
                    format: 'xml',
                    path: currentNodePath, // <-- Assign calculated path
                    level: level,
                    order: order,
                    childrenIds: [], // Will be populated by child traversals
                    metadata: {
                        xml: {
                            namespace: element.namespaceURI || undefined,
                            // Determine self-closing more reliably might be hard with DOMParser alone
                            // isSelfClosing: element.childNodes.length === 0 && !element.textContent // Heuristic?
                        }
                    }
                };

                const universalNode: UniversalFlowNode = {
                    id: currentUniversalId,
                    type: 'universal',
                    data: nodeData,
                    position: { x: 0, y: 0 }, // Position will be calculated by layout later
                };
                nodes.push(universalNode);

                if (parentUniversalId) {
                    edges.push({
                        id: uuidv4(),
                        source: parentUniversalId,
                        target: currentUniversalId,
                        type: 'smoothstep', // Default edge type
                        data: { relationshipType: 'parent-child' },
                    });
                } else {
                    // This is the root element of the document
                    rootId = currentUniversalId;
                    nodeData.nodeSemanticType = 'root'; // Mark the root element
                }

                // Recursively traverse child nodes - Pass current path as parentPath
                let childOrder = 0;
                element.childNodes.forEach(child => {
                    const childId = traverse(child, currentUniversalId, level + 1, childOrder, currentNodePath);
                    if (childId && nodeData.childrenIds) {
                        nodeData.childrenIds.push(childId);
                        childOrder++; // Increment order only for actual nodes created
                    }
                });
                break;

            case Node.TEXT_NODE:
                const textContent = xmlNode.nodeValue?.trim();
                if (textContent) { // Only create nodes for non-empty text
                    currentUniversalId = uuidv4();
                    // --- Path Calculation for Text ---
                    const textSegment = '/#text[' + order + ']';
                    currentNodePath = parentPath + textSegment; // Text nodes always have a parent element

                    const textNodeData: UniversalFlowNodeData = {
                        sourceElement: xmlNode,
                        name: '', // Text nodes don't have a tag name
                        value: textContent,
                        attributes: {}, // Text nodes don't have attributes
                        nodeSemanticType: 'value',
                        format: 'xml',
                        path: currentNodePath,
                        level: level,
                        order: order,
                    };
                    nodes.push({
                        id: currentUniversalId,
                        type: 'universal',
                        data: textNodeData,
                        position: { x: 0, y: 0 },
                    });
                    if (parentUniversalId) {
                        edges.push({
                            id: uuidv4(),
                            source: parentUniversalId,
                            target: currentUniversalId,
                            type: 'smoothstep',
                            data: { relationshipType: 'parent-child' },
                        });
                    } else {
                        // This case should ideally not happen for valid XML with a root
                        console.warn("Text node found without a parent element:", textContent);
                    }
                }
                break;

            case Node.COMMENT_NODE:
                currentUniversalId = uuidv4();
                // --- Path Calculation for Comment ---
                const commentSegment = '/#comment[' + order + ']';
                currentNodePath = parentPath + commentSegment; // Comments should have a parent

                const commentNodeData: UniversalFlowNodeData = {
                    sourceElement: xmlNode,
                    name: '', // Comments don't have a tag name
                    attributes: {}, // Comments don't have attributes
                    nodeSemanticType: 'comment',
                    format: 'xml',
                    path: currentNodePath,
                    level: level,
                    order: order,
                    metadata: {
                        comment: xmlNode.nodeValue || '',
                    },
                };
                nodes.push({
                    id: currentUniversalId,
                    type: 'universal',
                    data: commentNodeData,
                    position: { x: 0, y: 0 },
                });
                if (parentUniversalId) {
                    edges.push({
                        id: uuidv4(),
                        source: parentUniversalId,
                        target: currentUniversalId,
                        type: 'smoothstep',
                        data: { relationshipType: 'parent-child' },
                    });
                } else {
                    // This case should ideally not happen for valid XML with a root
                    console.warn("Comment node found without a parent element:", xmlNode.nodeValue);
                }
                break;

            case Node.PROCESSING_INSTRUCTION_NODE:
                if (parentUniversalId) {
                    const parentNode = nodes.find(n => n.id === parentUniversalId);
                    const pi = xmlNode as ProcessingInstruction;
                    if (parentNode?.data) {
                        if (!parentNode.data.metadata) parentNode.data.metadata = {};
                        if (!parentNode.data.metadata.xml) parentNode.data.metadata.xml = {};
                        parentNode.data.metadata.xml.processingInstruction = {
                            target: pi.target,
                            data: pi.data
                        };
                        // Make a shallow copy to trigger reactivity if needed (though likely not needed here)
                        // parentNode.data = { ...parentNode.data };
                    }
                } else {
                    // Handle top-level PIs if necessary (e.g., create a special node)
                    console.warn("Top-level processing instruction found:", xmlNode.nodeValue);
                }
                break;

            // Other node types (CDATA, DocumentType, etc.) are ignored for now
        }
        return currentUniversalId;
    }

    // Start traversal from the document's root element
    if (xmlDoc.documentElement) {
        traverse(xmlDoc.documentElement, null, 0, 0, ''); // Initial parentPath is empty string
    } else {
        console.warn("XML document has no root element during transformation.");
    }

    return { nodes, edges, rootId };
}


/**
 * Parses an XML string into Universal Flow format using the browser's DOMParser.
 * This function combines parsing and transformation.
 *
 * @param content The XML string content.
 * @returns A ParseUniversalResult object containing UniversalFlowNodes and Edges.
 */
export function parse(content: string): ParseUniversalResult {
    let xmlDoc: Document;

    // --- Step 1: Parse XML to DOM (Logic from xmlDomParser.ts) ---
    try {
        const parser = new DOMParser();
        xmlDoc = parser.parseFromString(content, 'text/xml');

        const parserError = xmlDoc.getElementsByTagName('parsererror');
        if (parserError.length > 0) {
            const errorMessage = parserError[0].textContent?.split('\n')[0] || 'Unknown parsing error reported by DOMParser';
            console.error('[domUniversalParser] DOMParser reported error:', parserError[0].innerHTML);
            return {
                success: false,
                error: `XML Parsing Error: ${errorMessage}`,
                nodes: [],
                edges: [],
                rootId: null,
            };
        }

        if (!xmlDoc.documentElement) {
            return {
                success: false,
                error: 'XML Parsing Error: No document root element found.',
                nodes: [],
                edges: [],
                rootId: null,
            };
        }

    } catch (err: any) {
        console.error('[domUniversalParser] Unexpected error during DOM parsing:', err);
        return {
            success: false,
            error: `Unexpected XML Parser Error: ${err.message || 'Unknown error'}`,
            nodes: [],
            edges: [],
            rootId: null,
        };
    }

    // --- Step 2: Transform DOM to Universal Flow Format ---
    try {
        const transformResult = transformDomToUniversal(xmlDoc);

        return {
            success: true,
            nodes: transformResult.nodes,
            edges: transformResult.edges,
            rootId: transformResult.rootId,
            rawDocument: xmlDoc // Optionally pass the raw DOM
        };
    } catch (transformError: any) {
        console.error('[domUniversalParser] Error during transformation:', transformError);
        return {
            success: false,
            error: `Transformation Error: ${transformError.message || 'Unknown error'}`,
            nodes: [],
            edges: [],
            rootId: null,
        };
    }
} 